////////////////////////////////////////////////////////////////////////////////
// Filename: graphicsclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include "graphicsclass.h"


GraphicsClass::GraphicsClass()
{
	m_D3D = 0;
	m_Camera = 0;
	//m_Model = 0;
	m_Sun_Model = 0;
	m_LightShader = 0;

	/*
	m_Light1 = 0;
	m_Light2 = 0;
	m_Light3 = 0;
	m_Light4 = 0;*/
}


GraphicsClass::GraphicsClass(const GraphicsClass& other)
{
}


GraphicsClass::~GraphicsClass()
{
}


bool GraphicsClass::Initialize(int screenWidth, int screenHeight, HWND hwnd)
{
	bool result;

		
	// Create the Direct3D object.
	m_D3D = new D3DClass;
	if(!m_D3D)
	{
		return false;
	}

	// Initialize the Direct3D object.
	result = m_D3D->Initialize(screenWidth, screenHeight, VSYNC_ENABLED, hwnd, FULL_SCREEN, SCREEN_DEPTH, SCREEN_NEAR);
	if(!result)
	{
		MessageBox(hwnd, L"Could not initialize Direct3D.", L"Error", MB_OK);
		return false;
	}

	// Create the camera object.
	m_Camera = new CameraClass;
	if(!m_Camera)
	{
		return false;
	}

	// Create the model object.
	/*m_Model = new ModelClass;
	if(!m_Model)
	{
		return false;
	}

	// Initialize the model object.
	result = m_Model->Initialize(m_D3D->GetDevice(), L"../Engine/data/jupiter_surface.jpg", "../Engine/data/sphere.txt");
	if(!result)
	{
		MessageBox(hwnd, L"Could not initialize the model object.", L"Error", MB_OK);
		return false;
	}*/
	// Create the sunmodel object.
	m_Sun_Model = new ModelClass;
	if(!m_Sun_Model)
	{
		return false;
	}

	// Initialize the model object.
	result = m_Sun_Model->Initialize(m_D3D->GetDevice(), L"../Engine/data/SunTexture.png", "../Engine/data/sphere.txt");
	if(!result)
	{
		MessageBox(hwnd, L"Could not initialize the model object.", L"Error", MB_OK);
		return false;
	}

	// Create the light shader object.
	m_LightShader = new LightShaderClass;
	if(!m_LightShader)
	{
		return false;
	}

	// Initialize the light shader object.
	result = m_LightShader->Initialize(m_D3D->GetDevice(), hwnd);
	if(!result)
	{
		MessageBox(hwnd, L"Could not initialize the light shader object.", L"Error", MB_OK);
		return false;
	}

	sunsystems = new struct sunsystemstruct[numSunsystems];
	if(sunsystems==NULL)
		return false;
	for(int i = 0;i<numSunsystems;i++) {
		sunsystems[i].system.initialize(hwnd, m_D3D);
		for(int j = 0;j<3;j++) {
			float tempPos = (((float)rand()-(float)rand())/RAND_MAX) * 100.0f;
			switch(j) {
			case 0:
				sunsystems[i].pos.x = tempPos;
				break;
			case 1:
				sunsystems[i].pos.y = tempPos;
				break;
			default:
				sunsystems[i].pos.z = tempPos;
			}
		}
		sunsystems[i].pointlight = new LightClass;
		if(!sunsystems[i].pointlight)
		{
			return false;
		}
		D3DXVECTOR4 sc = sunsystems[i].system.getSunColor();
		// Initialize the first light object.
		sunsystems[i].pointlight->SetDiffuseColor(sc.x, sc.y, sc.z,sc.w);
		sunsystems[i].pointlight->SetPosition(sunsystems[i].pos.x,sunsystems[i].pos.y,sunsystems[i].pos.z);
	}

	return true;
}


void GraphicsClass::Shutdown()
{

	/*
	// Release the light objects.
	if(m_Light1)
	{
		delete m_Light1;
		m_Light1 = 0;
	}

	if(m_Light2)
	{
		delete m_Light2;
		m_Light2 = 0;
	}

	if(m_Light3)
	{
		delete m_Light3;
		m_Light3 = 0;
	}

	if(m_Light4)
	{
		delete m_Light4;
		m_Light4 = 0;
	}
	*/
	// Release the light shader object.
	if(m_LightShader)
	{
		m_LightShader->Shutdown();
		delete m_LightShader;
		m_LightShader = 0;
	}

	// Release the model object.
	/*if(m_Model)
	{
		m_Model->Shutdown();
		delete m_Model;
		m_Model = 0;
	}*/
	// Release the sunmodel object.
	if(m_Sun_Model)
	{
		m_Sun_Model->Shutdown();
		delete m_Sun_Model;
		m_Sun_Model = 0;
	}
	// Release the camera object.
	if(m_Camera)
	{
		delete m_Camera;
		m_Camera = 0;
	}

	// Release the Direct3D object.
	if(m_D3D)
	{
		m_D3D->Shutdown();
		delete m_D3D;
		m_D3D = 0;
	}

	return;
}


bool GraphicsClass::Frame(float rotationY, float rotationZ, float forward, float right)
{
	// Set the position of the camera.
	//m_Camera->SetPosition(0.0f, 0.0f, -10.0f);
	m_Camera->SetMovement(forward,right);
	// Set the rotation of the camera.
	m_Camera->SetRotation(0.0f, rotationY, rotationZ);
	Render();
	return true;
}

void GraphicsClass::Render()
{
	D3DXMATRIX worldMatrix, viewMatrix, projectionMatrix;
	D3DXVECTOR4 diffuseColor[4];
	D3DXVECTOR3 lightPosition[4];
	
	float positionX, positionY, positionZ;
	float distance[4];
	/*
	// Create the diffuse color array from the four light colors.
	diffuseColor[0] = m_Light1->GetDiffuseColor();
	diffuseColor[1] = m_Light2->GetDiffuseColor();
	diffuseColor[2] = m_Light3->GetDiffuseColor();
	diffuseColor[3] = m_Light4->GetDiffuseColor();
	*/
	for(int i = 0;i<numSunsystems;i++) {
		diffuseColor[i] = sunsystems[i].pointlight->GetDiffuseColor();
		lightPosition[i] = sunsystems[i].pointlight->GetPosition();
	}
	/*
	// Create the light position array from the four light positions.
	lightPosition[0] = m_Light1->GetPosition();
	lightPosition[1] = m_Light2->GetPosition();
	lightPosition[2] = m_Light3->GetPosition();
	lightPosition[3] = m_Light4->GetPosition();
	*/
	// Clear the buffers to begin the scene.
	m_D3D->BeginScene(0.0f, 0.0f, 0.0f, 1.0f);

	// Generate the view matrix based on the camera's position.
	m_Camera->Render();

	// Get the world, view, and projection matrices from the camera and d3d objects.
	m_D3D->GetWorldMatrix(worldMatrix);
	m_Camera->GetViewMatrix(viewMatrix);
	m_D3D->GetProjectionMatrix(projectionMatrix);

	// Put the model vertex and index buffers on the graphics pipeline to prepare them for drawing.
	m_Sun_Model->Render(m_D3D->GetDevice());
	for(int i = 0;i<numSunsystems;i++) {
		sunsystems[i].system.frame();
		//Render Sun
		D3DXMATRIX translationMatrix, scalingMatrix;
		D3DXMatrixTranslation(&translationMatrix, sunsystems[i].pos.x, sunsystems[i].pos.y, sunsystems[i].pos.z); 
		D3DXMatrixScaling(&scalingMatrix, sunsystems[i].system.getSunScale(), sunsystems[i].system.getSunScale(), sunsystems[i].system.getSunScale());
		worldMatrix = scalingMatrix*translationMatrix;
		for(int k=0;k<numSunsystems;k++) {
			distance[k] = calcDistance(sunsystems[i].pos.x, sunsystems[i].pos.y, sunsystems[i].pos.z, lightPosition[k]);
		}
		// Render the model using the light shader and the light arrays.
		m_LightShader->Render(m_D3D->GetDevice(), m_Sun_Model->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix,
				m_Sun_Model->GetTexture(), diffuseColor, lightPosition, distance, ((float)i+1));
		for(int j = 0;j<sunsystems[i].system.getModelCount();j++) {
			sunsystems[i].system.getPlanetposition(positionX, positionY, positionZ, j);
			//TODO: Speichern der Sonnensystempositionen und verrechnen
			positionX+=sunsystems[i].pos.x;
			positionY+=sunsystems[i].pos.y;
			positionZ+=sunsystems[i].pos.z;
			for(int k=0;k<numSunsystems;k++) {
				distance[k] = calcDistance(positionX, positionY, positionZ, lightPosition[k]);
			}
			// Move the model to the location it should be rendered at.
			D3DXMATRIX translationMatrix, scalingMatrix, rotation;
			D3DXMatrixTranslation(&translationMatrix, positionX, positionY, positionZ); 
			sunsystems[i].system.getPlanetrotation(j,rotation);
			D3DXMatrixScaling(&scalingMatrix, sunsystems[i].system.getPlanetScale(j), sunsystems[i].system.getPlanetScale(j), sunsystems[i].system.getPlanetScale(j));
			worldMatrix = scalingMatrix*rotation*translationMatrix;
			// Render the model using the light shader and the light arrays.
			m_LightShader->Render(m_D3D->GetDevice(), sunsystems[i].system.getModel(j)->GetIndexCount(), worldMatrix, viewMatrix, projectionMatrix,
					sunsystems[i].system.getModel(j)->GetTexture(), diffuseColor, lightPosition, distance,0.0f);
		}
	}
	// Present the rendered scene to the screen.
	m_D3D->EndScene();

	return;
}

float GraphicsClass::calcDistance(float x1,float y1,float z1, D3DXVECTOR3 pos2) {
	return sqrtf((x1-pos2.x)*(x1-pos2.x) + (y1-pos2.y)*(y1-pos2.y) + (z1-pos2.z)*(z1-pos2.z));
}